package com.yi.demo.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yi.entity.Record;
import com.yi.entity.Wallet;
import com.yi.mapper.RecordMapper;
import com.yi.mapper.WalletMapper;
import com.yi.service.WalletService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Service
public class WalletServiceImpl extends ServiceImpl<WalletMapper, Wallet> implements WalletService {

    @Resource
    private WalletMapper walletMapper;

    @Resource
    private RecordMapper recordMapper;

    /**
     * 获取钱包余额
     *
     * @param userId 用户id
     * @return 钱包余额
     */
    @Override
    public BigDecimal getMoney(Integer userId) {
        // 判断用户id是否为空
        if (null == userId) {
            // 用户id为空，
            return null;
        }

        // 获取用户id对应的钱包记录
        Wallet wallet = walletMapper.selectOne(Wrappers.<Wallet>lambdaQuery().eq(Wallet::getUserId, userId));

        // 判断记录是否为空
        if (null != wallet) {
            return wallet.getMoney();
        }
        // 记录为空说明该用户并不存在，返回null
        return null;
    }

    /**
     * 钱包扣费的方法
     *
     * @param userId 用户id
     * @param cost   用户的花费
     * @return 一个 map。key 对应相应状态码，value 对应状态信息
     */
    @Override
    public Map<Integer, String> consume(Integer userId, BigDecimal cost) {
        // 返回的对象
        HashMap<Integer, String> res = new HashMap<>();

        // 判断属性是否为空，以及属性是否合法
        if (null == userId || null == cost || cost.compareTo(new BigDecimal("0")) < 0) {
            //返回错误信息
            res.put(600, "错误的参数");
            return res;
        }

        // 获取对应的钱包金额
        Wallet wallet = walletMapper.selectOne(Wrappers.<Wallet>lambdaQuery().eq(Wallet::getUserId, userId));
        BigDecimal money = wallet.getMoney();

        // 判断金额是否为空，为空说明该用户id是不存在的
        if (null == money) {
            //返回错误信息
            res.put(600, "错误的参数");
            return res;
        }

        // 判断钱包余额是否足够扣除这次的花费
        if (money.compareTo(cost) < 0) {
            res.put(610, "账户余额不足");
            return res;
        }

        // 账户余额足够，扣除花费金额。使用字符串初始化的BigDecimal是为了精确小数
        BigDecimal theMoney = new BigDecimal(money + "");
        BigDecimal theCost = new BigDecimal(cost + "");
        wallet.setMoney(theMoney.subtract(theCost));
        walletMapper.updateById(wallet);

        // 生成流水记录，保存到数据库中
        Record record = new Record();
        record.setUserId(wallet.getUserId());
        record.setMoney(cost.negate());
        record.setCreateTime(new Date());
        record.setStatus(0);
        recordMapper.insert(record);

        // 返回成功信息
        res.put(200, "成功");
        return res;
    }

    /**
     * 用户退款的方法
     * ps：本来这个方法传入的参数应该是一个流水记录的数据传输对象。但是这里我偷懒直接使用 Integer
     *
     * @param recordId 流水记录的id
     * @return 一个 map。key 对应相应状态码，value 对应状态信息
     */
    @Override
    public Map<Integer, String> refund(Integer recordId) {
        // 返回的对象
        HashMap<Integer, String> res = new HashMap<>();
        if (null == recordId) {
            res.put(600, "错误的参数");
            return res;
        }

        // 获取流水记录
        Record record = recordMapper.selectOne(Wrappers.<Record>lambdaQuery().eq(Record::getId, recordId));

        // 流水记录对象为空，说明传入的id有误
        if (null == record || record.getStatus() == 1) {
            res.put(600, "错误的参数");
            return res;
        }

        // 获取需要退款的金额
        BigDecimal amount = record.getMoney().negate();

        // 修改钱包余额
        Wallet wallet = walletMapper.selectOne(Wrappers.<Wallet>lambdaQuery().eq(Wallet::getUserId, record.getUserId()));
        wallet.setMoney(wallet.getMoney().add(amount));
        walletMapper.updateById(wallet);

        // 添加流水记录
        Record refundRecord = new Record();
        refundRecord.setUserId(wallet.getUserId());
        refundRecord.setMoney(amount);
        refundRecord.setCreateTime(new Date());
        refundRecord.setStatus(1);
        recordMapper.insert(refundRecord);

        res.put(200, "成功");
        return res;
    }
}
